package com.yf.exam.modules.tmpl.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yf.base.api.api.dto.BaseIdRespDTO;
import com.yf.base.api.api.dto.PagingReqDTO;
import com.yf.base.api.exception.ServiceException;
import com.yf.base.utils.AbcTags;
import com.yf.base.utils.BeanMapper;
import com.yf.base.utils.CalcUtils;
import com.yf.base.utils.DecimalUtils;
import com.yf.exam.enums.TmplJoinType;
import com.yf.exam.modules.exam.service.ExamService;
import com.yf.exam.modules.paper.dto.ext.PaperGroupExtDTO;
import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO;
import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO;
import com.yf.exam.modules.paper.service.PaperService;
import com.yf.exam.modules.tmpl.dto.OpenAITemplQuDTO;
import com.yf.exam.modules.tmpl.dto.TmplDTO;
import com.yf.exam.modules.tmpl.dto.ext.*;
import com.yf.exam.modules.tmpl.entity.Tmpl;
import com.yf.exam.modules.tmpl.entity.TmplGroup;
import com.yf.exam.modules.tmpl.entity.TmplGroupRule;
import com.yf.exam.modules.tmpl.mapper.TmplMapper;
import com.yf.exam.modules.tmpl.service.TmplGroupRuleService;
import com.yf.exam.modules.tmpl.service.TmplGroupService;
import com.yf.exam.modules.tmpl.service.TmplQuService;
import com.yf.exam.modules.tmpl.service.TmplService;

import com.yf.repo.enums.QuType;
import com.yf.repo.modules.qu.dto.QuAnswerDTO;
import com.yf.repo.modules.qu.dto.ext.QuDetailDTO;
import com.yf.repo.modules.qu.service.QuService;
import com.yf.system.modules.dict.dto.SysDicValueDTO;
import com.yf.system.modules.dict.service.SysDicValueService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;

/**
 * <p>
 * 试卷业务实现类
 * </p>
 *
 * @author 聪明笨狗
 * @since 2021-04-25 13:59
 */
@Service
public class TmplServiceImpl extends ServiceImpl<TmplMapper, Tmpl> implements TmplService {

    @Autowired
    private TmplGroupService tmplGroupService;

    @Autowired
    private TmplGroupRuleService tmplGroupRuleService;

    @Autowired
    private TmplQuService tmplQuService;

    @Autowired
    private ExamService examService;

    @Autowired
    private PaperService paperService;

    @Autowired
    private SysDicValueService baseService;

    @Autowired
    private QuService quBaseService;

    @Override
    public IPage<TmplDTO> paging(PagingReqDTO<TmplDTO> reqDTO) {


        //查询条件
        QueryWrapper<Tmpl> wrapper = new QueryWrapper<>();

        // 请求参数
        TmplDTO params = reqDTO.getParams();

        if (params != null) {
            if (!StringUtils.isBlank(params.getCatId())) {
                wrapper.lambda().eq(Tmpl::getCatId, params.getCatId());
            }

            if (params.getJoinType() != null) {
                wrapper.lambda().eq(Tmpl::getJoinType, params.getJoinType());
            }

            if (!StringUtils.isBlank(params.getTitle())) {
                wrapper.lambda().like(Tmpl::getTitle, params.getTitle());
            }
        }

        // 排序
        wrapper.lambda().orderByDesc(Tmpl::getCreateTime);

        //获得数据
        IPage<Tmpl> page = this.page(reqDTO.toPage(), wrapper);
        //转换结果
        IPage<TmplDTO> pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference<Page<TmplDTO>>() {
        });
        return pageData;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseIdRespDTO save(TmplDetailDTO reqDTO) {

        // 保存基本信息
        Tmpl tmpl = new Tmpl();
        BeanMapper.copy(reqDTO, tmpl);



        // 手动填写ID
        if (StringUtils.isBlank(tmpl.getId())) {
            tmpl.setId(IdWorker.getIdStr());
        }else{
           int count = paperService.countByTmpl(tmpl.getId());
           if(count > 0){
               throw new ServiceException("此试卷有正在进行的考试，不能修改！");
           }
        }

        // 先保存大题信息
        tmplGroupService.saveAll(tmpl, reqDTO.getGroupList());

        // 保存信息
        this.saveOrUpdate(tmpl);

        // 返回ID
        return new BaseIdRespDTO(tmpl.getId());

    }

    @Override
    public BaseIdRespDTO copy(String id) {

        // 查找数据
        TmplDetailDTO detail = this.findDetail(id);
        detail.setId(null);
        detail.setTitle(detail.getTitle() + "-复制");
        List<TmplGroupDetailDTO> list = detail.getGroupList();

        // 进行数据清理
        for (TmplGroupDetailDTO group : list) {
            group.setId(null);

            // 题目的
            List<TmplQuDetailDTO> quList = group.getQuList();
            if (!CollectionUtils.isEmpty(quList)) {
                for (TmplQuDetailDTO qu : quList) {
                    qu.setId(null);
                    List<TmplQuAnswerDetailDTO> answerList = qu.getAnswerList();
                    if (CollectionUtils.isEmpty(answerList)) {
                        continue;
                    }
                    for (TmplQuAnswerDetailDTO a : answerList) {
                        a.setId(null);
                    }
                }
            }

            List<TmplRuleDetailDTO> ruleList = group.getRuleList();
            if (!CollectionUtils.isEmpty(ruleList)) {
                for (TmplRuleDetailDTO rule : ruleList) {
                    rule.setId(null);
                }
            }
        }

        return this.save(detail);
    }

    @Override
    public TmplPreviewDTO preview(String id) {

        TmplPreviewDTO respDTO = new TmplPreviewDTO();

        // 基本信息
        Tmpl tmpl = this.getById(id);
        BeanMapper.copy(tmpl, respDTO);

        // 预览试卷
        List<PaperGroupExtDTO> groupList = this.findForCreate(id);

        // 加上编号
        this.cleanAndProcess(tmpl.getJoinType(), groupList);
        respDTO.setGroupList(groupList);
        return respDTO;
    }

    @Override
    public TmplDetailDTO findDetail(String id) {
        return baseMapper.findDetail(id);
    }

    @Override
    public TmplDTO findSimpleInfo(String id) {
        Tmpl tmpl = this.getById(id);
        TmplDTO respDTO = new TmplDTO();
        BeanMapper.copy(tmpl, respDTO);
        return respDTO;
    }

    @Override
    public List<PaperGroupExtDTO> findForCreate(String id) {

        Tmpl tmpl = this.getById(id);

        if(tmpl == null){
            throw new ServiceException("试卷模板不存在，无法创建考试！");
        }

        List<PaperGroupExtDTO> respList = new ArrayList<>();

        // 查找大题列表
        List<TmplGroup> groupList = tmplGroupService.listByTmpl(id);

        // 抽题和选题组卷，直接从库中找指定题目
        if (TmplJoinType.TYPE1.equals(tmpl.getJoinType()) || TmplJoinType.TYPE2.equals(tmpl.getJoinType())) {

            for (TmplGroup group : groupList) {
                PaperGroupExtDTO groupDTO = new PaperGroupExtDTO();
                BeanMapper.copy(group, groupDTO);
                // 组卷排序
                List<PaperQuDetailDTO> quList = tmplQuService.listForCreate12(group);
                // 设置题目表
                groupDTO.setQuList(quList);
                // 加入列表
                respList.add(groupDTO);
            }
        }

        // 按规则来组卷
        if (TmplJoinType.TYPE3.equals(tmpl.getJoinType())) {

            // 排除ID防止重复
            List<String> excludes = new ArrayList<>();

            for (TmplGroup group : groupList) {
                PaperGroupExtDTO groupDTO = new PaperGroupExtDTO();
                BeanMapper.copy(group, groupDTO);
                List<TmplGroupRule> rules = tmplGroupRuleService.listByGroup(group.getId());
                List<PaperQuDetailDTO> allList = new ArrayList<>();
                for (TmplGroupRule rule : rules) {
                    List<PaperQuDetailDTO> quList = tmplQuService.listForCreate3(excludes, group, rule);

                    if (CollectionUtils.isEmpty(quList) || quList.size() != rule.getNum()) {
                        throw new ServiceException("试卷生成失败，题库题目数量不足！");
                    }
                    // 以便排除
                    for (PaperQuDetailDTO item : quList) {
                        excludes.add(item.getQuId());
                    }
                    allList.addAll(quList);
                }
                // 设置题目表
                groupDTO.setQuList(allList);
                // 加入列表
                respList.add(groupDTO);
            }
        }

        return respList;
    }

    @Transactional
    @Override
    public void deleteByIds(List<String> ids) {

        for(String id: ids){
            int count = examService.countByTmpl(id);
            if(count > 0){
                throw new ServiceException("有关联的考试，无法删除！！");
            }
        }

        this.removeByIds(ids);
    }

    /**
     * 对接子路创建试卷
     * @param openAITemplQuDTO
     * @return
     */
    @Override
    public BaseIdRespDTO openPaper(OpenAITemplQuDTO openAITemplQuDTO) {
        TmplDetailDTO tmplDetailDTO=new TmplDetailDTO();
        String templId = baseService.findTableId("tmpl_catalog", openAITemplQuDTO.getTemplType());
        if (templId.equals("")){
            SysDicValueDTO sysDicValueDTO=new SysDicValueDTO();
            sysDicValueDTO.setDicCode("tmpl_catalog");
            sysDicValueDTO.setTitle(openAITemplQuDTO.getTemplType());
            sysDicValueDTO.setRemark(openAITemplQuDTO.getTemplType());
            sysDicValueDTO.setParentId("0");
            baseService.save(sysDicValueDTO);
            templId = baseService.findTableId("tmpl_catalog", openAITemplQuDTO.getTemplType());
        }
        //创建试卷
        //试卷分类
        tmplDetailDTO.setCatId(templId);
        //组卷方式
        tmplDetailDTO.setJoinType(1);
        //题目数量
        tmplDetailDTO.setQuCount(openAITemplQuDTO.getQuestionIdList().size());

        tmplDetailDTO.setTitle(openAITemplQuDTO.getTemplTitle());
        //遍历检索
        List<Map<String, Object>> questionIdList = openAITemplQuDTO.getQuestionIdList();
        //封装groupList
        List<TmplGroupDetailDTO> list = groupTmplGroup(questionIdList);
        tmplDetailDTO.setGroupList(list);
        System.out.println("数据列表:"+list.toString());
        int totalScore=0;
        for (Map<String, Object> map:questionIdList){
            String score=map.get("score").toString();
            totalScore+=Integer.parseInt(score);
        }
        tmplDetailDTO.setTotalScore(BigDecimal.valueOf(totalScore));
        return this.save(tmplDetailDTO);
    }

    /**
     * 封装试题列表
     * @param tmplQuList
     * @return
     */
    private List<TmplGroupDetailDTO> groupTmplGroup(List<Map<String,Object>> tmplQuList){
        List<TmplGroupDetailDTO> list=new ArrayList<>();
        //单选题列表
        List<TmplQuDetailDTO> oneSelectQuList=new ArrayList<>();
        //填空题
        List<TmplQuDetailDTO> enterQuList = new ArrayList<>();
        //简答题
        List<TmplQuDetailDTO> easyReQuList = new ArrayList<>();
        //填空题
        List<TmplQuDetailDTO> checkQuList=new ArrayList<>();
        for (Map<String,Object> map:tmplQuList){
            String Id=map.get("id").toString();
            Integer quType=Integer.parseInt(map.get("quType").toString());
            //根据id检索试题类型
            QuDetailDTO detail = quBaseService.detail(Id);

            //封装题目
            TmplQuDetailDTO quDetailDTO=new TmplQuDetailDTO();
            quDetailDTO.setContent(detail.getContent());
            quDetailDTO.setAnalysis(detail.getAnalysis());
            quDetailDTO.setQuId(detail.getId());
            quDetailDTO.setQuType(detail.getQuType());
            quDetailDTO.setQuType_dictText(detail.getQuType_dictText());
            quDetailDTO.setScore(BigDecimal.valueOf(Integer.parseInt(map.get("score").toString())));
            List<TmplQuAnswerDetailDTO> answerList=new ArrayList<>();
            List<QuAnswerDTO> quAnswerList=detail.getAnswerList();
            if (quAnswerList!=null) {
                //封装答案
                for (QuAnswerDTO quAnswerDTO : quAnswerList) {
                    TmplQuAnswerDetailDTO tempAnswer = new TmplQuAnswerDetailDTO();
                    tempAnswer.setAnswerId(quAnswerDTO.getId());
                    tempAnswer.setContent(quAnswerDTO.getContent());
                    tempAnswer.setIsRight(quAnswerDTO.getIsRight());
                    tempAnswer.setPathScore(quAnswerDTO.getPathScore());
                    tempAnswer.setTag(quAnswerDTO.getTag());
                    answerList.add(tempAnswer);
                }
            }
            quDetailDTO.setAnswerList(answerList);
            if (quType==1){
                //单选题
                oneSelectQuList.add(quDetailDTO);
            }else if (quType==5){
                //填空题
                enterQuList.add(quDetailDTO);
            }else if (quType==4){
                //简答题
                easyReQuList.add(quDetailDTO);
            } else if (quType==3) {
                //判断题
                checkQuList.add(quDetailDTO);
            }
        }
        if (oneSelectQuList.size()!=0){
            //添加单选题
            TmplGroupDetailDTO tmplGroupDetailDTO = new TmplGroupDetailDTO();
            //添加试题
            tmplGroupDetailDTO.setQuList(oneSelectQuList);
            //选项乱序
            tmplGroupDetailDTO.setItemRand(false);
            //选错也给分
            tmplGroupDetailDTO.setPathScore(false);
            //单题分数
            BigDecimal score=oneSelectQuList.get(0).getScore();
            tmplGroupDetailDTO.setPerScore(score);
            //试题数量
            tmplGroupDetailDTO.setQuCount(oneSelectQuList.size());
            //试题乱序
            tmplGroupDetailDTO.setQuRand(false);
            //试题类型
            tmplGroupDetailDTO.setQuType("1");
            //分数
            tmplGroupDetailDTO.setTitle("单选题");
            //总分数
            oneSelectQuList.get(0).getScore();
            BigDecimal totalScore=BigDecimal.valueOf(score.scale()*oneSelectQuList.size());
            tmplGroupDetailDTO.setTotalScore(totalScore);
            list.add(tmplGroupDetailDTO);
        }
        if (enterQuList.size() != 0) {
            //添加填空题
            TmplGroupDetailDTO tmplGroupDetailDTO = new TmplGroupDetailDTO();
            //添加试题
            tmplGroupDetailDTO.setQuList(enterQuList);
            //选项乱序
            tmplGroupDetailDTO.setItemRand(false);
            //选错也给分
            tmplGroupDetailDTO.setPathScore(false);
            //单题分数
            BigDecimal score=enterQuList.get(0).getScore();
            tmplGroupDetailDTO.setPerScore(score);
            //试题数量
            tmplGroupDetailDTO.setQuCount(enterQuList.size());
            //试题乱序
            tmplGroupDetailDTO.setQuRand(false);
            //试题类型
            tmplGroupDetailDTO.setQuType("5");
            //分数
            tmplGroupDetailDTO.setTitle("填空题");
            //总分数
            enterQuList.get(0).getScore();
            BigDecimal totalScore=BigDecimal.valueOf(score.scale()*enterQuList.size());
            tmplGroupDetailDTO.setTotalScore(totalScore);
            list.add(tmplGroupDetailDTO);
        }
        if (easyReQuList.size() != 0) {
            //添加简答题
            TmplGroupDetailDTO tmplGroupDetailDTO = new TmplGroupDetailDTO();
            //添加试题
            tmplGroupDetailDTO.setQuList(easyReQuList);
            //选项乱序
            tmplGroupDetailDTO.setItemRand(false);
            //选错也给分
            tmplGroupDetailDTO.setPathScore(false);
            //单题分数
            BigDecimal score=easyReQuList.get(0).getScore();
            tmplGroupDetailDTO.setPerScore(score);
            //试题数量
            tmplGroupDetailDTO.setQuCount(easyReQuList.size());
            //试题乱序
            tmplGroupDetailDTO.setQuRand(false);
            //试题类型
            tmplGroupDetailDTO.setQuType("4");
            //分数
            tmplGroupDetailDTO.setTitle("简答题");
            //总分数
            easyReQuList.get(0).getScore();
            BigDecimal totalScore=BigDecimal.valueOf(score.scale()*easyReQuList.size());
            tmplGroupDetailDTO.setTotalScore(totalScore);
            list.add(tmplGroupDetailDTO);
        }
        if (checkQuList.size()!=0){
            //添加判断题
            TmplGroupDetailDTO tmplGroupDetailDTO = new TmplGroupDetailDTO();
            //添加试题
            tmplGroupDetailDTO.setQuList(checkQuList);
            //选项乱序
            tmplGroupDetailDTO.setItemRand(false);
            //选错也给分
            tmplGroupDetailDTO.setPathScore(false);
            //单题分数
            BigDecimal score=checkQuList.get(0).getScore();
            tmplGroupDetailDTO.setPerScore(score);
            //试题数量
            tmplGroupDetailDTO.setQuCount(checkQuList.size());
            //试题乱序
            tmplGroupDetailDTO.setQuRand(false);
            //试题类型
            tmplGroupDetailDTO.setQuType("3");
            //分数
            tmplGroupDetailDTO.setTitle("判断题");
            //总分数
            checkQuList.get(0).getScore();
            BigDecimal totalScore=BigDecimal.valueOf(score.scale()*checkQuList.size());
            tmplGroupDetailDTO.setTotalScore(totalScore);
            list.add(tmplGroupDetailDTO);
        }
        return list;
    }



    /**
     * 进行排序处理挂载关系
     *
     * @param joinType
     * @param groupList
     */
    private void cleanAndProcess(Integer joinType, List<PaperGroupExtDTO> groupList) {

        int i = 1;
        for (PaperGroupExtDTO group : groupList) {
            List<PaperQuDetailDTO> quList = group.getQuList();
            for (PaperQuDetailDTO qu : quList) {
                qu.setSort(i);

                // 大题分数
                if (TmplJoinType.TYPE3.equals(joinType)) {
                    qu.setScore(group.getPerScore());

                    // 组合题填分
                    if(QuType.MIX.equals(qu.getQuType())){
                        List<PaperQuDetailDTO> subList = qu.getSubList();
                        // 填充随机的分数
                        List<BigDecimal> scoreList = CalcUtils.avgSplit(group.getPerScore(), subList.size());
                        for(int j=0; j<subList.size(); j++){
                            subList.get(j).setScore(scoreList.get(j));
                        }
                    }
                }





                List<PaperQuAnswerExtDTO> answerList = qu.getAnswerList();
                if (!CollectionUtils.isEmpty(answerList)) {
                    int j = 0;
                    for (PaperQuAnswerExtDTO answer : answerList) {
                        if (TmplJoinType.TYPE3.equals(joinType)) {
                            answer.setPathScore(DecimalUtils.zero());
                        }
                        answer.setSort(j);
                        answer.setAbc(AbcTags.get(j));
                        j++;
                    }
                }
                i++;
            }
        }
    }

}
